package com.aliang.shopping.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliang.shopping.common.PageResult;
import com.aliang.shopping.common.Result;
import com.aliang.shopping.common.ResultCodeEnum;
import com.aliang.shopping.contact.ResultMsgContact;
import com.aliang.shopping.contact.SqlColumnConstant;
import com.aliang.shopping.exception.DataException;
import com.aliang.shopping.log.annotation.OperateLog;
import com.aliang.shopping.log.enums.OperateType;
import com.aliang.shopping.model.converter.GoodsTypeConverter;
import com.aliang.shopping.model.dto.common.PageDTO;
import com.aliang.shopping.model.dto.common.UpdateStatusDTO;
import com.aliang.shopping.model.dto.goodsType.GoodsTypeInsertDTO;
import com.aliang.shopping.model.dto.goodsType.GoodsTypeUpdateDTO;
import com.aliang.shopping.model.enums.UserTypeEnum;
import com.aliang.shopping.model.po.GoodsType;
import com.aliang.shopping.model.vo.TreeVO;
import com.aliang.shopping.model.vo.goods.GoodsTypeOption;
import com.aliang.shopping.model.vo.goods.GoodsTypeVO;
import com.aliang.shopping.security.PreventRepeatSubmit;
import com.aliang.shopping.security.auth.UserHolder;
import com.aliang.shopping.service.GoodsTypeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/goodsType")
@AllArgsConstructor
public class GoodsTypeController {

    private final GoodsTypeService goodsTypeService;
    private final GoodsTypeConverter goodsTypeConverter;
    private final RedisTemplate<String, String> redisTemplate;

    /**
     * 商品分类插入
     *
     * @param insertDTO
     * @return
     */
    @PostMapping("/insert")
    @ApiOperation("商品分类插入")
    @PreventRepeatSubmit
    @OperateLog(title = "商品分类插入", type = OperateType.INSERT)
    public Result<String> insertGoodsType(@RequestBody GoodsTypeInsertDTO insertDTO) {

        if (UserHolder.getUserRole() < UserTypeEnum.ADMIN.getCode()) {
            //没有权限
            throw new DataException(ResultCodeEnum.NOT_AUTHORIZED);
        }
        //名字不能为空
        if (StrUtil.isBlank(insertDTO.getName())) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //转换数据
        GoodsType poByInsertDTO = this.goodsTypeConverter.toPoByInsertDTO(insertDTO);
        this.goodsTypeService.save(poByInsertDTO);
        //清空缓存
        redisTemplate.delete(SqlColumnConstant.GOODS_TYPE_OPTION);
        return Result.ok(ResultMsgContact.INSERT_SUCCESS);
    }

    /**
     * 商品分类删除
     *
     * @param ids
     * @return
     */
    @DeleteMapping("/del")
    @ApiOperation("商品分类删除")
    @PreventRepeatSubmit
    @OperateLog(title = "商品分类删除", type = OperateType.DELETE)
    public Result<String> delGoodsType(@RequestBody List<Long> ids) {
        //查询数据是否存在子级目录
        LambdaQueryWrapper<GoodsType> wrapper = new LambdaQueryWrapper<GoodsType>()
                .in(GoodsType::getParentId, ids);
        int count = this.goodsTypeService.count(wrapper);
        //存在子级目录，不允许删除
        if (count > 0) {
            throw new DataException(ResultCodeEnum.HAS_CHILDREN_BY_DEL);
        }
        this.goodsTypeService.removeByIds(ids);
        //清空缓存
        redisTemplate.delete(SqlColumnConstant.GOODS_TYPE_OPTION);
        return Result.ok(ResultMsgContact.DELETE_SUCCESS);
    }

    /**
     * 商品分类更改
     *
     * @param updateDTO
     * @return
     */
    @PutMapping("/update")
    @ApiOperation("商品分类更改")
    @PreventRepeatSubmit
    @OperateLog(title = "商品分类更改", type = OperateType.UPDATE)
    public Result<String> updateGoodsType(@RequestBody GoodsTypeUpdateDTO updateDTO) {
        //名字不能为空
        if (StrUtil.isBlank(updateDTO.getName())) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //转换数据
        GoodsType goodsType = this.goodsTypeConverter.toPoByUpdateDTO(updateDTO);
        this.goodsTypeService.saveOrUpdate(goodsType);
        //清空缓存
        redisTemplate.delete(SqlColumnConstant.GOODS_TYPE_OPTION);
        return Result.ok(ResultMsgContact.UPDATE_SUCCESS);
    }

    /**
     * 商品分类状态更改
     *
     * @param updateDTO
     * @return
     */
    @PutMapping("/update_static")
    @ApiOperation("商品分类状态更改")
    @PreventRepeatSubmit
    @OperateLog(title = "商品分类状态更改", type = OperateType.UPDATE_STATUS)
    public Result<String> updateGoodsTypeStatic(@RequestBody UpdateStatusDTO updateDTO) {
        //必要字段校验
        if (BeanUtil.isEmpty(updateDTO)) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //如果是禁用，确保子类都禁用再禁用父类
        if (SqlColumnConstant.STATUS_FAIL.equals(updateDTO.getStatus())) {
            //查询是否存在子级分类
            LambdaQueryWrapper<GoodsType> wrapper = new LambdaQueryWrapper<GoodsType>()
                    .eq(GoodsType::getParentId, updateDTO.getId())
                    .eq(GoodsType::getStatus, SqlColumnConstant.STATUS_OK);
            int count = this.goodsTypeService.count(wrapper);
            if (count > 0) {
                throw new DataException(ResultCodeEnum.HAS_CHILDREN_BY_UPDATE);
            }
        }
        //转换数据
        GoodsType goodsType = this.goodsTypeConverter.toPoByUpdateStaticDTO(updateDTO);
        this.goodsTypeService.updateById(goodsType);
        //清空缓存
        redisTemplate.delete(SqlColumnConstant.GOODS_TYPE_OPTION);
        return Result.ok(ResultMsgContact.UPDATE_SUCCESS);
    }

    /**
     * 商品分类分页搜索
     */
    @GetMapping("/getPage")
    @ApiOperation("商品分类分页搜索")
    public Result<PageResult<GoodsTypeVO>> queryGoodsTypePage(PageDTO pageDTO) {
        //必要字段校验
        if (ObjectUtil.hasNull(pageDTO.getPageSize(), pageDTO.getPageNum())) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //查询数据
        PageResult<GoodsTypeVO> result = this.goodsTypeService.selectPage(pageDTO);
        return Result.ok(result);
    }


    /**
     * 商品分类选项查询
     */
    @GetMapping("/getGoodsTypeOption")
    @ApiOperation("商品分类选项查询")
    public Result<List<GoodsTypeOption>> getGoodsTypeOption() {
        //查询缓存数据
        if (Boolean.TRUE.equals(redisTemplate.hasKey(SqlColumnConstant.GOODS_TYPE_OPTION))) {
            String json = redisTemplate.opsForValue().get(SqlColumnConstant.GOODS_TYPE_OPTION);
            return Result.ok(JSONUtil.toList(json, GoodsTypeOption.class));
        }
        //构造查询条件
        LambdaQueryWrapper<GoodsType> wrapper = new LambdaQueryWrapper<GoodsType>()
                .select(GoodsType::getId, GoodsType::getName, GoodsType::getParentId, GoodsType::getIcon)
                .eq(GoodsType::getStatus, SqlColumnConstant.STATUS_OK)
                .orderByAsc(GoodsType::getOrderNum);
        //查找数据库
        List<GoodsType> goodsTypes = this.goodsTypeService.list(wrapper);
        if (goodsTypes.isEmpty()) {
            return Result.fail();
        }
        // 根据父Id分组
        Map<Long, List<GoodsType>> map = goodsTypes.stream().collect(Collectors.groupingBy(GoodsType::getParentId));
        //获取一级数据
        List<GoodsTypeOption> treeVOS = map.get(0L).stream()
                .map(goodsTypeConverter::toFrontTreeVo).collect(Collectors.toList());
        //设置二级分类
        treeVOS.forEach(treeVO ->
        {
            //根据是否存在父类Id判断是否存在二级分类
            if (map.containsKey(treeVO.getValue())) {
                //获取二级分类并转化成属性数组
                List<TreeVO> collect = map.get(treeVO.getValue())
                        .stream().map(goodsTypeConverter::toTreeVo).collect(Collectors.toList());
                treeVO.setChildren(collect);
            }
        });
        //存入数据库
        redisTemplate.opsForValue().set(SqlColumnConstant.GOODS_TYPE_OPTION, JSONUtil.toJsonStr(treeVOS));
        // 返回数据
        return Result.ok(treeVOS);
    }
}
